﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

/// <summary>
/// 普通键值对
/// </summary>
public class KeyValue
{
    public string key;
    public string value;
    public KeyValue() { }
    public KeyValue(string k, string v) { key = k;value = v; }
}
/// <summary>
/// ini数组数据
/// </summary>
public class IniMate
{
    public string index;
    public List<KeyValue> values = new List<KeyValue>();
}

/// <summary>
/// ini节点
/// </summary>
public class INISection
{
    Dictionary<string, List<Action<INISection>>> ValueListener;
    public void AddListener(string key,Action<INISection> action)
    {
        if (ValueListener == null)
            ValueListener = new Dictionary<string, List<Action<INISection>>>();
        if (ValueListener.ContainsKey(key))
        {
            var list = ValueListener[key];
            if (list.Contains(action))
                return;
            list.Add(action);
            return;
        }
        List<Action<INISection>> actions = new List<Action<INISection>>();
        actions.Add(action);
        ValueListener.Add(key, actions);
    }
    public void DeleteListener(string key, Action<INISection> action)
    {
        if (ValueListener == null)
            return;
        if (ValueListener.ContainsKey(key))
        {
            var list = ValueListener[key];
            list.Remove(action);
            if (list.Count == 0)
                ValueListener.Remove(key);
        }
    }
    /// <summary>
    /// 节点名称
    /// </summary>
    public string Name;
    /// <summary>
    /// 键值对数据集合
    /// </summary>
    public List<KeyValue> Values = new List<KeyValue>();
    /// <summary>
    /// 数组数据集合
    /// </summary>
    public List<IniMate> Mates = new List<IniMate>();
    /// <summary>
    /// 添加一组数据
    /// </summary>
    /// <param name="key"></param>
    /// <param name="value"></param>
    public void Add(string key, string value)
    {
        key = key.Trim();
        if (value == null)
            value = "";
        else value = value.Trim();
        var ss = key.Split('\\');
        if (ss.Length > 1)
        {
            Add(ss[0], ss[1], value);//数组
        }
        else
        {
            for (int i = 0; i < Values.Count; i++)
                if (Values[i].key == key)
                {
                    if(Values[i].value != value)
                    {
                        Values[i].value = value;
                        if (ValueListener != null)
                        {
                            if (ValueListener.ContainsKey(key))
                            {
                                var list = ValueListener[key];
                                for (int j = 0; j < list.Count; j++)
                                    if (list[j] != null)
                                        list[j](this);
                            }
                        }
                    }
                    return;
                }
            var kv = new KeyValue();
            kv.key = key;
            kv.value = value;
            Values.Add(kv);
            if (ValueListener != null)
            {
                if (ValueListener.ContainsKey(key))
                {
                    var list = ValueListener[key];
                    for (int j = 0; j < list.Count; j++)
                        if (list[j] != null)
                            list[j](this);
                }
            }
        }
    }
    /// <summary>
    /// 添加数组的值
    /// </summary>
    /// <param name="index">元素索引</param>
    /// <param name="key"></param>
    /// <param name="value"></param>
    public void Add(string index, string key, string value)
    {
        key = key.Trim();
        value = value.Trim();
        IniMate mate = null;
        for (int i = 0; i < Mates.Count; i++)
            if (Mates[i].index == index)
            {
                mate = Mates[i];
                break;
            }
        if (mate == null)
        {
            mate = new IniMate();
            mate.index = index;
            var kv = new KeyValue();
            kv.key = key;
            kv.value = value;

            mate.values.Add(kv);
            Mates.Add(mate);
        }
        else
        {
            var v = mate.values;
            for (int i = 0; i < v.Count; i++)
                if (v[i].key == key)
                {
                    v.RemoveAt(i);
                    break;
                }
            var kv = new KeyValue();
            kv.key = key;
            kv.value = value;
            mate.values.Add(kv);
        }
    }
    /// <summary>
    /// 获取值
    /// </summary>
    /// <param name="key">键</param>
    /// <returns></returns>
    public string GetValue(string key)
    {
        for (int i = 0; i < Values.Count; i++)
            if (key == Values[i].key)
                return Values[i].value;
        return null;
    }
    /// <summary>
    /// 获取值
    /// </summary>
    /// <param name="key">键</param>
    /// <returns></returns>
    public string GetValue(string key,ref int index)
    {
        for (int i = 0; i < Values.Count; i++)
            if (key == Values[i].key)
            {
                index = i;
                return Values[i].value; 
            }
        return null;
    }
    /// <summary>
    /// 读取一个简单的对象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public T ReadObject<T>(INIReader ini = null)where T:class,new()
    {
        var obj = new T();
        Type tInfo = obj.GetType();
        var fs = tInfo.GetFields();
        if(fs!=null)
        {
            for (int i = 0; i < fs.Length; i++)
            {
                var p = fs[i];
                string key = p.Name;
                string v = GetValue(key);
                if (v != null & v != "")
                {
                    var type = p.FieldType;
                    var r = ParseValue(type, v, ini);
                    if (r != null)
                        p.SetValue(obj, r);
                }
            }
        }
        return obj;
    }
    /// <summary>
    /// 读取一个简单的对象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public object ReadObject(Type type, INIReader ini = null)
    {
        var obj = Activator.CreateInstance(type);
        var fs = type.GetFields();
        if (fs != null)
        {
            for (int i = 0; i < fs.Length; i++)
            {
                var p = fs[i];
                string key = p.Name;
                string v = GetValue(key);
                if (v != null & v != "")
                {
                    var ft = p.FieldType;
                    var r = ParseValue(ft, v, ini);
                    if (r != null)
                        p.SetValue(obj, r);
                }
            }
        }
        return obj;
    }
    object ParseValue(Type type, string value,INIReader ini)
    {
        if (type.Name == "String")
        {
            return value;
        }
        if (type.IsPrimitive)
        {
            var result = Convert.ChangeType(value, type, System.Globalization.CultureInfo.InvariantCulture);
            return result;
        }
        if (type == typeof(decimal))
        {
            decimal result;
            //System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture,
            decimal.TryParse(value, out result);
            return result;
        }
        if (value == "null")
        {
            return null;
        }
        if (type.IsEnum)
        {
            if (value[0] == '"')
                value = value.Substring(1, value.Length - 2);
            try
            {
                return Enum.Parse(type, value, false);
            }
            catch
            {
                return 0;
            }
        }
        if (type.IsArray)
        {
            var son = type.GetElementType();
            string[] dat = value.Split(',');
            if (son.Name == "String")
                return dat;
            var arr = Array.CreateInstance(son, dat.Length);
            if(son.IsEnum)
            {
                for (int i = 0; i < dat.Length; i++)
                {
                    arr.SetValue(Enum.Parse(son, dat[i], false),i);
                }
            }
            else if(son.IsPrimitive)
            {
                for (int i = 0; i < dat.Length; i++)
                {
                    arr.SetValue(Convert.ChangeType(dat[i], son, System.Globalization.CultureInfo.InvariantCulture), i);
                }
            }else if(son.IsClass)
            {
                if (ini != null)
                    for (int i = 0; i < dat.Length; i++)
                    {
                        arr.SetValue(ini.ReadObject(dat[i], son), i);
                    }
            }
            return arr;
        }
        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
        {
            var son = type.GenericTypeArguments[0];
            string[] dat = value.Split(',');
            if (son.Name == "String")
                return new List<string>(dat);
            var list = Activator.CreateInstance(type) as IList;
            for (int i = 0; i < dat.Length; i++)
            {
                list.Add(Convert.ChangeType(dat[i], son, System.Globalization.CultureInfo.InvariantCulture));
            }
            return list;
        }
        if (type== typeof(UnityEngine.Vector3))
        {
            string v = GetFloatArray(value);
            UnityEngine.Vector3 r = UnityEngine.Vector3.zero;
            unsafe
            {
                GetFloatArray((float*)&r, v);
            }
            return r;
        }
        if(type== typeof(UnityEngine.Color))
        {
            string v = GetFloatArray(value);
            UnityEngine.Color c = UnityEngine.Color.white;
            unsafe
            {
                GetFloatArray((float*)&c, v);
            }
            return c;
        }
        if (type == typeof(UnityEngine.Color32))
        {
            string v = GetFloatArray(value);
            UnityEngine.Color32 c = UnityEngine.Color.white;
            unsafe
            {
                GetByteArray((byte*)&c, v);
            }
            return c;
        }
        return null;
    }
    /// <summary>
    /// 将对象的所有字段内容写入
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public bool WriteObject(object obj)
    {
        Type tInfo = obj.GetType();
        foreach (FieldInfo p in tInfo.GetFields())
        {
            string key = p.Name;
            object value = p.GetValue(obj);
            if (value != null)
                Add(key, value.ToString());
        }
        return true;
    }

    static StringBuilder builder;
    /// <summary>
    /// 以数字为目标剔除字符串中多余的字符,剔除后格式为 1.444,5.666,2.433
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    static string GetFloatArray(string str)
    {
        if (str == null)
            return null;
        if (builder == null)
            builder = new StringBuilder();
        else builder.Clear();
        for(int i=0;i<str.Length;i++)
        {
            var c = str[i];
            if (c == ',' | c == '.')
                builder.Append(c);
            else if (c >= '0' & c <= '9')
                builder.Append(c);
        }
        return builder.ToString();
    }
    unsafe static void GetFloatArray(float* p, string str)
    {
        string[] ss = str.Split(',');
        for (int i = 0; i < ss.Length; i++)
        {
            float a = 0;
            float.TryParse(ss[i], out a);
            p[i] = a;
        }
    }
    unsafe static void GetByteArray(byte* p, string str)
    {
        string[] ss = str.Split(',');
        for (int i = 0; i < ss.Length; i++)
        {
            byte a = 0;
            byte.TryParse(ss[i], out a);
            p[i] = a;
        }
    }
}